﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cars
{
    public delegate void CarFoundEvent (CarInfo car, ref bool cancel);

    public class KslCrawler
    {
        // this seems strange but they are distinct. cancel means the user asked to cancel where
        // more refers to whether we have pages left to check or have not reached the AdId where
        // we should stop.
        private bool _cancelled = false;
        private bool _more = true;
        public CarFoundEvent OnCarFound { get; set; }

        public void Crawl(string stopAtAdId, int startAtPageNumber, int stopAtPageNumber, List<CarFilter> filters)
        {
            int pageIdx = startAtPageNumber;
            while ((_more) && (!_cancelled) && (pageIdx <= stopAtPageNumber))
            {
                LoadPage(pageIdx, stopAtAdId, filters);

                pageIdx += 1;
            }
        }

        public void CancelCrawl()
        {
            _cancelled = true;
        }

        private void LoadPage(int pageIdx, string stopAtAdId, List<CarFilter> filters)
        {
            bool _more = true;

            string response = WebUtils.HttpGet(string.Format("http://www.ksl.com/index.php?sid=&nid=443&tab=list&pid={0}", pageIdx));

            int idx = 0;
            while ((!_cancelled) && (_more))
            {
                TextBlock carBlock = CarInfo.getTextBlock(response, idx, "<div class=\"adBox\">", false);

                // if there is no remaining carBlock, means we are done with this page
                if (carBlock.StartIdx == -1)
                {
                    break;
                }

                // do some stuff
                KslCarInfo car = new KslCarInfo();
                car.ParseListView(carBlock.Text);

                // if this is the car we are supposed to stop on then quit
                if (car.AdId == stopAtAdId)
                {
                    _more = false;
                    break;
                }

                // now check our  filters to see if we should notify
                foreach (CarFilter filter in filters)
                {
                    if (((filter.Year == 0) || (filter.Year == car.Year)) &&
                        ((filter.Make == "*") || (filter.Make == car.Make)) &&
                        ((filter.Model == "*") || (filter.Model == car.Model)) &&
                        ((filter.MaxPrice == 0) || (car.Price <= filter.MaxPrice)) &&
                        ((filter.MinPrice == 0) || (car.Price >= filter.MinPrice)))
                    {
                        if (OnCarFound != null)
                        {
                            OnCarFound(car, ref _cancelled);
                        }

                        // we only want to send one notification even if it matches multiple filters
                        break;
                    }
                }

                // make sure we look for the next one
                idx = carBlock.EndIdx;
            }
        }
    }
}
